/* Copyright (C) 
 * 
 * Disclaim
 * This program is the property of AI Speech Ltd. It shall be communicated to
 * authorized personnel only. It is not to be disclosed outside the group without
 * prior written consent. If you are not sure if you’re authorized to read this
 * program, please contact info@aispeech.com before reading.
 * 
 */

/**
 * @file wtk_utils.h
 * 
 * @brief wtk_utils: wtk开发中可能会用到的一些辅助性函数
 * 
 * @author wxm71 <weixing.mei@aispeech.com>
 * 
 * @version v.0.0.1
 * 
 * @date 2014-09-28
 * 
 * Last modified: 2014-12-18 14:27
 */


#ifndef ___WXM71___WTK_UTILS__HEADER___
#define ___WXM71___WTK_UTILS__HEADER___

#ifdef __cplusplus
extern "C" {
#endif

#include "wtk/core/cfg/wtk_local_cfg.h"

#include "wtk_utils_ustr.h"
#include "wtk_utils_debug.h"
#include "wtk_utils_str_iter.h"
#include "wtk_utils_array.h"
#include "wtk_utils_str_dis.h"

// get value from json
#define wtk_utils_get_json_i(json, name) cJSON_GetObjectItem(json, name)->valueint
#define wtk_utils_get_json_f(json, name) cJSON_GetObjectItem(json, name)->valuedouble
#define wtk_utils_get_json_s(json, name) cJSON_GetObjectItem(json, name)->valuestring


// string compare, string -> wtk_string_t, str -> C style string
#define wtk_utils_str_equ_str(s1, s2) ((NULL==s1&&NULL==s2) || (strlen(s1)==strlen(s2) && 0==strncmp(s1, s2, strlen(s1))))
#define wtk_utils_string_equ_str(str, s1)  ((NULL==str&&NULL==s1) || ((str)->len==strlen(s1) && 0==strncmp((str)->data, s1, (str)->len)) )
#define wtk_utils_string_equ_string(str1, str2)  ((NULL==(str1)&&NULL==(str2)) || ((str1)->len==(str2)->len && 0==strncmp((str1)->data, (str2)->data, (str1)->len)))
#define wtk_utils_str_equ(s, s2, l2)        (  (NULL==s&&NULL==s2) || ( (strlen(s)==l2) && 0==strncmp(s, s2, l2) )  )
#define wtk_utils_string_equ(str, s2, l2)   (  (NULL==str&&NULL==s2) || ( ((str)->len==l2) && 0==strncmp((str)->data, s2, l2) )  )
#define wtk_utils_s_equ(s1, l1, s2, l2) (  (NULL==s1&&NULL==s2) || ( (l1==l2) && 0==strncmp(s1, s2, l1) )  )


// compare ignore case, ic <==> ignore case
#define wtk_utils_str_ic_equ_str(s1, s2) ((NULL==s1&&NULL==s2) || (strlen(s1)==strlen(s2) && 0==strncasecmp(s1, s2, strlen(s1))))
#define wtk_utils_string_ic_equ_str(str, s1)  ((NULL==str&&NULL==s1) || ((str)->len==strlen(s1) && 0==strncasecmp((str)->data, s1, (str)->len)) )
#define wtk_utils_string_ic_equ_string(str1, str2)  ((NULL==str1&&NULL==str2) || (str1->len==str2->len && 0==strncasecmp(str1->data, str2->data, str1->len)))
#define wtk_utils_str_ic_equ(s, s2, l2)        (  (NULL==s&&NULL==s2) || ( (strlen(s)==l2) && 0==strncasecmp(s, s2, l2) )  )
#define wtk_utils_string_ic_equ(str, s2, l2)   (  (NULL==str&&NULL==s2) || ( ((str)->len==l2) && 0==strncasecmp((str)->data, s2, l2) )  )
#define wtk_utils_s_ic_equ(s1, l1, s2, l2) (  (NULL==s1&&NULL==s2) || ( (l1==l2) && 0==strncasecmp(s1, s2, l1) )  )


#define WTK_MAKE_PAIR_S(s)  s, strlen(s)
#define WTK_MAKE_PAIR_STR(str) (str)->data, (str)->len


#define wtk_robin_is_full(r) ((r)->used>=(r)->nslot)

#define FLOATCMP 1e-6


/**
 * @brief output an array in one row, seperate with ,
 */
void wtk_utils_row_dump_arr_i(wtk_array_t* arr, wtk_strbuf_t *buf);
void wtk_utils_row_dump_arr_f(wtk_array_t* arr, wtk_strbuf_t *buf);


/**
 * @brief like join in python
 *
 * @param arr array to be join
 * @param sep seperator
 * @param buf output buffer
 * @reset whether reset buffer before join
 */
void wtk_utils_join_arr_i(wtk_array_t* arr, char sep, wtk_strbuf_t *buf, int reset);
void wtk_utils_join_arr_f(wtk_array_t* arr, char sep, wtk_strbuf_t *buf, int reset);
void wtk_utils_join_arr_str(wtk_array_t* arr, char sep, wtk_strbuf_t *buf, int reset);


/**
 * @brief random sample index from an array, promise while time of sample -> inf, 
 * p(i) = arr[i]
 */
int wtk_utils_randsample(wtk_array_t *arr);


/**
 * @brief split a string with given character
 */
wtk_array_t* wtk_utils_string_split_c(wtk_heap_t *heap, char *str, int len, char c);
#define wtk_utils_string_split_c_s(heap, s, c)	   ( NULL==s ? NULL : wtk_utils_string_split_c(heap, s, strlen(s), c) )
#define wtk_utils_string_split_c_str(heap, str, c) ( NULL==str||0==(str)->len? NULL: wtk_utils_string_split_c(heap, (str)->data, (str)->len, c) )


/**
 * @brief find a character in a given string
 *
 * @return if find, return first appearance position of 'c', otherwise return -1
 */
int wtk_utils_string_find_c(const char* p, int len, char c);
#define wtk_utils_string_find_c_s(s, c)	    wtk_utils_string_find_c(s, strlen(s), c)
#define wtk_utils_string_find_c_str(str, c)  wtk_utils_string_find_c((str)->data, (str)->len, c)


/**
 * @brief like sub in awk
 */
wtk_string_t* wtk_utils_string_sub(wtk_heap_t *heap, char *raw, int rlen, char *pat, int plen, char *newVal, int nlen);


/**
 * @brief like gsub in awk
 */
wtk_string_t* wtk_utils_string_gsub(wtk_heap_t *heap, char *raw, int rlen, char *pat, int plen, char *newVal, int nlen);


/**
 * @brief add data to a hash 
 *
 * @note as wtk_hash_add make a shallow copy of key, which may lead problem, this function will make a deep copy of key
 */
void wtk_utils_hash_uniq_add(wtk_str_hash_t *hash, char *key, int len, void* val);
#define wtk_utils_hash_uniq_add_s(hash, s, val) wtk_utils_hash_uniq_add(hash, s, strlen(s), val)
#define wtk_utils_hash_uniq_add_str(hash, str, val) wtk_utils_hash_uniq_add(hash, (str)->data, (str)->len, val)


/**
 * @brief time to minutes
 */
int wtk_utils_time2min(char *data, int len, wtk_strbuf_t *buf, int reset);
#define wtk_utils_time2min_s(s, buf, reset) wtk_utils_time2min(s, strlen(s), buf, reset)
#define wtk_utils_time2min_str(str,buf, reset) wtk_utils_time2min((str)->data, (str)->len, buf, reset)


/**
 * @brief wtk_string_t to C style string
 */
char* wtk_utils_string_to_str(wtk_strbuf_t* buf, char *data, int len); 
#define wtk_utils_string_to_str_s(buf, s) wtk_utils_string_to_str(buf, s, strlen(s))
#define wtk_utils_string_to_str_str(buf, str) wtk_utils_string_to_str(buf, (str)->data, (str)->len)



wtk_array_t* wtk_utils_local_cfg_find_array_s(wtk_local_cfg_t* lc, char *data, int len);


void wtk_utils_buf_width_append(wtk_strbuf_t *buf, char *data, int len, int w);
#define wtk_utils_buf_width_append_s(buf, s, w) wtk_utils_buf_width_append(buf, s, strlen(s), w)
#define wtk_utils_buf_width_append_str(buf, str, w) wtk_utils_buf_width_append(buf, (str)->data, (str)->len, w)


/**
 * @brief remove an item from a wtk_string_t* array
 *
 * @param arr, array of wtk_string_t*
 * @param data, item to be remove
 * @param len length of data
 *
 * @note this function don't actually remove string from array, but set it as an empty string({data=NULL, len=0})
 */
void wtk_utils_remove_str_from_arr(wtk_array_t *arr, char *data, int len);
#define wtk_utils_remove_str_from_arr_s(arr, s) wtk_utils_remove_str_from_arr(arr, s, strlen(s))
#define wtk_utils_remove_str_from_arr_str(arr, str) wtk_utils_remove_str_from_arr(arr, (str)->data, (str)->len)


/**
 * @brief whether a string is an item of array
 *
 * @return return 1 if exist, otherwise return 0
 */
int wtk_utils_string_arr_has(wtk_array_t *arr, char *data, int len);
#define wtk_utils_string_arr_has_s(arr, s) wtk_utils_string_arr_has(arr, s, strlen(s))
#define wtk_utils_string_arr_has_str(arr, str) wtk_utils_string_arr_has(arr, (str)->data, (str)->len)


/**
 * @brief return the first appearance in the array
 *
 * @return return the 1st appearce id if exist, otherwise return -1
 */
int wtk_utils_string_arr_get_idx(wtk_array_t *arr, char *data, int len);
#define wtk_utils_string_arr_get_idx_s(arr, s) wtk_utils_string_arr_get_idx(arr, s, strlen(s))
#define wtk_utils_string_arr_get_idx_str(arr, str) wtk_utils_string_arr_get_idx(arr, (str)->data, (str)->len)

/**
 * @brief get dir name from a string
 *
 * @note function implement in wtk have to malloc space, this function is an in-place operation
 */
wtk_string_t wtk_utils_dir_name(char *data, int len, char sep);
#define wtk_utils_dir_name_s(s, sep) wtk_utils_dir_name(s, strlen(s), sep)
#define wtk_utils_dir_name_str(str, sep) wtk_utils_dir_name((str)->data, (str)->len, sep)


/**
 * @brief get file name from string
 */
wtk_string_t wtk_utils_base_name(char *data, int len, char sep);
#define wtk_utils_base_name_s(s, sep) wtk_utils_base_name(s, strlen(s), sep)
#define wtk_utils_base_name_str(str, sep) wtk_utils_base_name((str)->data, (str)->len, sep)


wtk_string_t* wtk_utils_string_array_get(wtk_array_t *arr, char *data, int len);
#define wtk_utils_string_array_get_s(arr, s) wtk_utils_string_array_get(arr, s, strlen(s))
#define wtk_utils_string_array_get_str(arr, str) wtk_utils_string_array_get(arr, (str)->data, (str)->len)


/**
 * @brief whether to array of wtk_string_t* is equal, don't request item appear in same order
 */
int wtk_utils_string_array_equ(wtk_array_t *arr1, wtk_array_t *arr2);


/**
 * @brief remove leading blank 
 */
wtk_string_t wtk_utils_string_trim_left(char *data, int len);


/**
 * @brief remove tailing blank
 */
wtk_string_t wtk_utils_string_trim_right(char *data, int len);


/**
 * @brief remove leading and tailing blank
 */
wtk_string_t wtk_utils_string_trim(char *data, int len);


wtk_string_t wtk_utils_string_sub_word(char *data, int len, int start, int end);
#define wtk_utils_string_sub_word_s(s, start, end) wtk_utils_string_sub_word((s), strlen(s), start, end)
#define wtk_utils_string_sub_word_str(str, start, end) wtk_utils_string_sub_word((str)->data, (str)->len, start, end)


#define wtk_utils_ptr_swap(ptr1, ptr2)  { void *ptr = ptr1; ptr1 = ptr2; ptr2=ptr; }


/**
 * @brief remove an item from array, and insert last item in it's place 
 */
void wtk_utils_array_remove(wtk_array_t *arr, int idx);


/**
 * @brief remove an item from array, shift items after it 1 position forward
 */
void wtk_utils_array_shift_remove(wtk_array_t *arr, int idx);


/**
 * @brief translate an utf8 stream to a utf8 code
 */
unsigned int wtk_utils_utf8_to_num(char *data, int len);


/**
 * @brief translate utf8 code to string
 */
void wtk_utils_num_to_uft8(unsigned int raw);


/**
 * @brief read short value from bytes stream 
 *
 * @param data bytes stream
 * @param n number of short value to read
 * @param buf output buffer to receive short value
 */
void readShortsFromBytes(char *data, int n, unsigned short* buf);

void readIntsFromBytes(char *data, int n, unsigned int* buf);

void readLongsFromBytes(char *data, int n, unsigned long* buf);

#ifdef __cplusplus
};
#endif

#endif
